﻿#region Disclaimer / License
// Copyright (C) 2011, Kenneth Bergeron, IAP Worldwide Services, Inc
// NOAA :: National Marine Fisheries Service
// 
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
// 
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
// Lesser General Public License for more details.
// 
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
// 
#endregion
using System;
using System.Collections.Generic;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;

namespace CatchProcessing
{
    /// <summary>
    /// Print the Catch Report
    /// </summary>
    public partial class PrintFish
    {
        // The next record to print
        private int CurrentItem;
        // This prins from a DGV - to hadle the formatting and binding.
        private DataGridView FishGrid;
        /// <summary>
        /// Number of pages in the report
        /// </summary>
        public int NumberPages { get; set; }
        /// <summary>
        /// Print the Catch report
        /// </summary>
        /// <param name="aFishGrid">The DGV from which to print</param>
        /// <param name="aDocument">The doc to print to</param>
        public PrintFish(DataGridView aFishGrid, System.Drawing.Printing.PrintDocument aDocument)
        {
            FishGrid = aFishGrid;
            aDocument.BeginPrint += new System.Drawing.Printing.PrintEventHandler(this.PrintDocumentBeginPrint);
            aDocument.PrintPage += new System.Drawing.Printing.PrintPageEventHandler(this.PrintDocumentPrintPage);
            this.NumberPages = 0;
        }
        /// <summary>
        /// Shortcut for record at a DGV row index
        /// </summary>
        /// <param name="aRowIndex">DGV row index</param>
        /// <returns>FishRow at the index</returns>
        private DataSets.LocalDataSet.FishRow FishRowAt(int aRowIndex)
        {
            if (aRowIndex > this.FishGrid.Rows.Count || aRowIndex < 0) return null;
            if (this.FishGrid.Rows[aRowIndex].DataBoundItem is DataSets.LocalDataSet.FishSamplesRow)
                return (DataSets.LocalDataSet.FishRow)this.FishGrid.Rows[aRowIndex].DataBoundItem;
            return (DataSets.LocalDataSet.FishRow)((DataRowView)this.FishGrid.Rows[aRowIndex].DataBoundItem).Row;
        }
        /// <summary>
        /// A place to store the report
        /// </summary>
        private CatchReport Report;
        /// <summary>
        /// BeginPrint event from the PrintDocument
        /// </summary>
        private void PrintDocumentBeginPrint(object sender, System.Drawing.Printing.PrintEventArgs e)
        {
            this.CurrentItem = 1;
            this.NumberPages = 0;
        }
        /// <summary>
        /// PrintPage event from the Printdocument
        /// </summary>
        private void PrintDocumentPrintPage(object sender, System.Drawing.Printing.PrintPageEventArgs e)
        {
            this.NumberPages++;
            e.Graphics.Clear(Color.White);
            string fontName = "Arial";
            using (Font HeaderFont = new Font(fontName, 8, System.Drawing.FontStyle.Bold))
            using (Font NormalFont = new Font(fontName, 8, System.Drawing.FontStyle.Regular))
            {
                // Create the report
                Report = MakeReport(e.Graphics, NormalFont, HeaderFont);
                float NormalHeight = NormalFont.GetHeight(e.Graphics) + 2;
                float HeaderHeight = HeaderFont.GetHeight(e.Graphics) + 2;
                float Y = e.MarginBounds.Top;
                // Print Page heading
                using (Font BigFont = new System.Drawing.Font(HeaderFont.FontFamily, 12))
                    e.Graphics.DrawString("Catch Processing "+ Report.Vessel+" Cruise "+Report.Cruise+ "   "+
                        DateTime.Now.ToString("dddd, dd MMMM yyyy hh:mm tt") + "  Page " + this.NumberPages.ToString(),
                        BigFont, System.Drawing.Brushes.Black, new PointF(e.MarginBounds.Left, 20));
                // Print report heading (it's the first line in 'Report')
                foreach (PrintItem Item in Report.Lines[0].Items)
                {
                    using (StringFormat sf = new StringFormat() { FormatFlags = StringFormatFlags.NoWrap, Alignment = Item.Align })
                    using (Brush Br = new SolidBrush(Item.Color))
                        e.Graphics.DrawString(Item.Text, HeaderFont, Br,
                            new RectangleF(e.MarginBounds.Left + Item.X, Y, Item.W, HeaderFont.Height), sf);
                }
                Y += HeaderHeight;
                // Print the detail lines
                while (CurrentItem < Report.Lines.Length && (Y < e.MarginBounds.Bottom))
                {
                    foreach (PrintItem Item in Report.Lines[CurrentItem].Items)
                    {
                        using (StringFormat sf = new StringFormat() { FormatFlags = StringFormatFlags.NoWrap, Alignment = Item.Align })
                        using (Brush Br = new SolidBrush(Item.Color))
                            e.Graphics.DrawString(Item.Text, NormalFont, Br,
                                new RectangleF(e.MarginBounds.Left + Item.X, Y, Item.W, NormalFont.Height), sf);
                    }
                    Y += NormalHeight;
                    this.CurrentItem++;
                }
                e.HasMorePages = (this.CurrentItem < this.Report.Lines.Length);
            }
        }
        /// <summary>
        /// A class to store the report
        /// </summary>
        private class CatchReport
        {
            public string Vessel { get; set; }
            public string Cruise { get; set; }
            public PrintLine[] Lines { get; set; }
            public CatchReport(string aVessel, string aCruise, PrintLine[] aLines)
            {
                Vessel = aVessel;
                Cruise = aCruise;
                Lines = aLines;
            }
        }
        /// <summary>
        /// A class to store a line
        /// </summary>
        private class PrintLine
        {
            public float Y { get; set; }
            public PrintItem[] Items;
            public void AddItem(PrintItem aItem)
            {
                List<PrintItem> Result = new List<PrintItem>(Items);
                Result.Add(aItem);
                Items = Result.ToArray();
            }
            public PrintLine(float aY, PrintItem aItem)
            {
                Items = new PrintItem[] { aItem };
                Y = aY;
            }
            public PrintLine(float aY)
            {
                Items = new PrintItem[0];
                Y = aY;
            }
        }
        /// <summary>
        /// A class to store a report element (parts of a line)
        /// </summary>
        private class PrintItem
        {
            public float X { get; set; }
            public float W { get; set; }
            public string Text { get; set; }
            public System.Drawing.Color Color { get; set; }
            public StringAlignment Align { get; set; }
            public PrintItem(float aX, float aW, string aText, System.Drawing.Color aColor, StringAlignment aAlign)
            {
                X = aX;
                W = aW;
                Text = aText;
                Color = aColor;
                Align = aAlign;
            }
            public PrintItem(float aX, float aW, string aText, StringAlignment aAlign)
            {
                X = aX;
                W = aW;
                Text = aText;
                Align = aAlign;
                Color = Color.Black;
            }
        }
        /// <summary>
        /// Create the report
        /// </summary>
        /// <param name="aGr">Draw to</param>
        /// <param name="aRegFont">Font for detail items</param>
        /// <param name="aHeaderFont">Font for header items</param>
        /// <returns>The report</returns>
        private CatchReport MakeReport(Graphics aGr, Font aRegFont, Font aHeaderFont)
        {
            // All the column widths
            Dictionary<DataGridViewColumn, float> Widths =
                (from DataGridViewColumn qC in this.FishGrid.Columns select qC)
                .ToDictionary(qC => qC, qC => aGr.MeasureString(qC.HeaderText, aHeaderFont).Width);
            // Go through the entire database getting the Maximum column widths
            foreach (DataGridViewRow dgv in this.FishGrid.Rows)
            {
                foreach (DataGridViewCell Cell in from DataGridViewCell qC in dgv.Cells where qC.Visible select qC)
                {
                    DataGridViewColumn C = this.FishGrid.Columns[Cell.ColumnIndex];
                    Widths[C] = Math.Max(aGr.MeasureString((string)Cell.FormattedValue, aRegFont).Width + 20, Widths[C]);
                }
            }
            // Lines of the report
            List<PrintLine> Lines = new List<PrintLine>();
            float LineNo = 0f;
            PrintLine Header = new PrintLine(LineNo);
            float X = 0f;
            // Print the column headers
            foreach (DataGridViewColumn Col in this.FishGrid.Columns)
            {
                if (Col.Visible)
                {
                    Header.AddItem(new PrintItem(X, Widths[Col], Col.HeaderText,
                        Col.DefaultCellStyle.ForeColor.ToArgb() == 0 ? this.FishGrid.ForeColor : Col.DefaultCellStyle.ForeColor,
                        Col.DefaultCellStyle.Alignment.ToString().Contains("Right") ? StringAlignment.Far : StringAlignment.Near));
                    X += Widths[Col];
                }
            }
            Lines.Add(Header);
            string Station = string.Empty;
            DataSets.LocalDataSet.FishRow fRow = null;
            // Print the report lines
            foreach (DataGridViewRow dgv in this.FishGrid.Rows)
            {
                fRow = FishRowAt(dgv.Index);
                if(Station != fRow.Station)
                    Lines.Add(new PrintLine(LineNo++, new PrintItem(0f, aGr.MeasureString("Station: " + fRow.Station, aHeaderFont).Width, 
                        "Station: "+fRow.Station, Color.Red, StringAlignment.Near)));
                Station = fRow.Station;
                PrintLine FishLine = new PrintLine(LineNo);
                LineNo++;
                X = 0f;
                // Print the data row elements
                foreach (DataGridViewCell Cell in from DataGridViewCell qC in dgv.Cells where qC.Visible select qC)
                {
                    DataGridViewColumn Col = this.FishGrid.Columns[Cell.ColumnIndex];
                    if (Cell.Style.ForeColor.ToArgb() != 0) Console.WriteLine("ASD");
                    //if (Col.DefaultCellStyle.Alignment == DataGridViewContentAlignment.MiddleRight)
                    //    Value = Value.PadLeft(18);  // must use formatstring...
                    FishLine.AddItem(new PrintItem(X, Widths[Col], (string)Cell.FormattedValue, 
                        Cell.Style.ForeColor.ToArgb() == 0 ? this.FishGrid.ForeColor : Cell.Style.ForeColor,
                        Col.DefaultCellStyle.Alignment.ToString().Contains("Right") ? StringAlignment.Far : StringAlignment.Near));
                    X += Widths[Col];
                }
                Lines.Add(FishLine);
                LineNo++;
                if (!fRow.IsCommentNull() && !string.IsNullOrEmpty(fRow.Comment))
                    Lines.Add(new PrintLine(LineNo++, new PrintItem(80f, aGr.MeasureString("Comment: "+fRow.Comment, aRegFont).Width, "Comment: "+fRow.Comment, StringAlignment.Near)));
                foreach (DataSets.LocalDataSet.FishSamplesRow sRow in fRow.GetFishSamplesRows())
                {
                    string Sub = sRow.ToString();
                    PrintLine SubLine = new PrintLine(LineNo++);
                    SubLine.AddItem(new PrintItem(80f, aGr.MeasureString(Sub, aRegFont).Width, Sub, StringAlignment.Near));
                    Lines.Add(SubLine);
                }
            }
            if (fRow == null) return new CatchReport(string.Empty, string.Empty, Lines.ToArray());
            return new CatchReport(fRow.VesselName, fRow.Cruise, Lines.ToArray());
        }
    }
}